package com.danicsoft.daide.serverclient;

import com.danicsoft.daide.command.OrderSpec;
import com.danicsoft.daide.command.UnitPos;
import com.danicsoft.daide.command.OrderSpec.ConvoyTarget;
import com.danicsoft.daide.command.OrderSpec.SupportTarget;
import com.danicsoft.daide.token.StandardToken;
import com.danicsoft.daide.token.Token;
import com.danicsoft.daide.token.TokenGroup;
import com.danicsoft.daide.token.TokenMap.Coasts;
import com.danicsoft.daide.token.TokenMap.Orders;
import com.danicsoft.daide.token.TokenMap.UnitTypes;

import dip.order.Order;
import dip.order.OrderFactory;
import dip.world.Coast;
import dip.world.Location;
import dip.world.Power;
import dip.world.Province;
import dip.world.Unit;
import dip.world.World;
import dip.world.Unit.Type;

/**
 * Contains a collection of functions for converting back between firefly types
 * and jDip types.
 * 
 * @author Daniel Yule (daniel.yule@gmail.com)
 * @version 1.0
 */
public class Adapter {

	/**
	 * Convert from DAIDE types to jDip types
	 * 
	 * @author Daniel Yule (daniel.yule@gmail.com)
	 * @version 1.0
	 */
	public static class DAIDEtojDip {

		/**
		 * Converts a Token representig a coast to a jDip class representing a
		 * coast.
		 * 
		 * @param coast
		 *        A StandardToken representing a coast.
		 * @return A jDip Coast object.
		 */
		public static Coast convertCoast(StandardToken coast) {
			switch (coast.getSubType()) {
				case Coasts.NEC:
				case Coasts.NCS:
					return Coast.NORTH;
				case Coasts.NWC:
				case Coasts.WCS:
					return Coast.WEST;
				case Coasts.SWC:
				case Coasts.SCS:
					return Coast.SOUTH;
				case Coasts.SEC:
				case Coasts.ECS:
					return Coast.EAST;

			}
			return Coast.UNDEFINED;
		}

		/**
		 * Convert a UnitPos object to a Location object.
		 * 
		 * @param position
		 *        The province location.
		 * @param world
		 *        The world to convert.
		 * @return A Location object.
		 */
		public static Location convertLocation(Token position, World world) {
			Coast coast;
			Province prov;
			if (position.isGroup()) {
				TokenGroup tGroup = (TokenGroup) position.clone();
				coast = convertCoast((StandardToken) tGroup.next());
				prov = convertProvince((StandardToken) tGroup.next(), world);
			}
			else {
				prov = convertProvince((StandardToken) position, world);
				if (prov.isLand())
					coast = Coast.LAND;
				else
					coast = Coast.SINGLE;
			}

			return new Location(prov, coast);
		}

		/**
		 * Converts an order into a jDip type of order.
		 * 
		 * @param order
		 *        The order to convert.
		 * @param power
		 *        The power we are moving for.
		 * @param myWorld
		 *        The world we are living in.
		 * @return A jDip style order.s
		 */
		public static Order convertOrder(OrderSpec order, Power power, World myWorld) {
			OrderFactory factory = OrderFactory.getDefault();
			Location loc = convertLocation(order.UnitPos.province, myWorld);
			Type type = convertType(order.UnitPos);
			switch (order.predicate.getSubType()) {
				case Orders.BLD:
					return factory.createBuild(power, loc, type);
				case Orders.CTO:
					return factory.createMove(power, loc, type, convertLocation(((OrderSpec.ConvoyMoveTarget) order.target).dstProv, myWorld), true);
				case Orders.CVY:
					ConvoyTarget target = (ConvoyTarget) order.target;
					return factory.createConvoy(power, loc, type, convertLocation(target.ConvoyUnit.province, myWorld), convertPower(target.ConvoyUnit.power, myWorld), convertType(target.ConvoyUnit), convertLocation(target.convoyingTo, myWorld));
				case Orders.DSB:
					return factory.createDisband(power, loc, type);
				case Orders.HLD:
					return factory.createHold(power, loc, type);
				case Orders.MTO:
					return factory.createMove(power, loc, type, convertLocation(((OrderSpec.MoveTarget) order.target).Province, myWorld));
				case Orders.REM:
					return factory.createRemove(power, loc, type);
				case Orders.RTO:
					return factory.createRetreat(power, loc, type, convertLocation(((OrderSpec.RetreatTarget) order.target).Province, myWorld));
				case Orders.SUP:
					OrderSpec.SupportTarget supTarget = (SupportTarget) order.target;
					if (supTarget.isForMove()) {
						return factory.createSupport(power, loc, type, convertLocation(supTarget.supportUnit.province, myWorld), convertPower(supTarget.supportUnit.power, myWorld), convertType(supTarget.supportUnit), convertLocation(supTarget.movingTo, myWorld));
					}
					else {
						return factory.createSupport(power, loc, type, convertLocation(supTarget.supportUnit.province, myWorld), convertPower(supTarget.supportUnit.power, myWorld), convertType(supTarget.supportUnit));
					}
				case Orders.WVE:
				default:
					return factory.createWaive(power, loc);
			}
		}

		/**
		 * Converts a Token representing a power to a jDip class representing a
		 * power.
		 * 
		 * @param power
		 *        A StandardToken representing the power to convert.
		 * @param world
		 *        The jDip world that we use to convert.
		 * @return A jDip Power object
		 */
		public static Power convertPower(StandardToken power, World world) {
			return world.getMap().getPower(power.toString());
		}

		/**
		 * Converts a Token representing a province to a jDip class representing
		 * a Province.
		 * 
		 * @param province
		 *        A StandardToken representing a province.
		 * @param world
		 *        The world to use to convert.
		 * @return A jDip Province Object.
		 */
		public static Province convertProvince(StandardToken province, World world) {
			return world.getMap().getProvince(province.toString());
		}

		/**
		 * Convert the unit position given to a jDip Type object
		 * 
		 * @param position
		 *        The position to convert.
		 * @return A jDip Type object.
		 */
		public static Type convertType(UnitPos position) {
			if (position.unit_type.getSubType() == UnitTypes.AMY) {
				return Unit.Type.ARMY;
			}
			return Unit.Type.FLEET;
		}

	}

	/**
	 * Converts between jDip types and DAIDE types.
	 * 
	 * @author Daniel Yule (daniel.yule@gmail.com)
	 * @version 1.0
	 */
	public static class jDipToDAIDE {
//		public static OrderSpec convertOrder(Order order, TokenMap tokenMap) {
//			if (order instanceof Build) {
//				return OrderSpec.getBuildOrder(convertLocation(order.getSource(), order.getPower(), order.getSourceUnitType(), tokenMap));
//			} else if (order instanceof Convoy) {
//				return OrderSpec.getConvoy(convertLocation(order.getSource(), order.getPower(), order.getSourceUnitType(), tokenMap), convertLocation(((Convoy)order).getConvoySrc(), ((Convoy)order).getConvoyedPower(), ((Convoy)order).getConvoyUnitType(), tokenMap), (StandardToken) convertProvince(((Convoy)order).getConvoyDest().getProvince(), ((Convoy)order).getConvoyDest().getCoast(), tokenMap));
//			}
//			
//			return null;
//		}

//		/**
//		 * Converts between a jDip location, power and unit type to a DAIDE
//		 * style UnitPos
//		 * 
//		 * @param source
//		 *        The source of movement
//		 * @param power
//		 *        The power that is moving
//		 * @param type
//		 *        The type of unit that is moving.
//		 * @return A DAIDE <code>UnitPos</code>
//		 */
//		public static UnitPos convertLocation(Location source, Power power, Type type, TokenMap tokenMap) {
//			UnitPos pos = new UnitPos();
//			pos.power = convertPower(power);
//			pos.province = convertProvince(source.getProvince(), source.getCoast(), tokenMap);
//			pos.unit_type = convertType(type);
//			return pos;
//		}
//
//		public static Token convertProvince(Province province, Coast coast, TokenMap tokenMap) {
//			try {
//				StandardToken ProvinceToken = tokenMap.convert(province.getShortName());
//				if(coast.NONE)
//			}
//			catch (InvalidTokenException e) {
//				return null;
//			}
//			
//		}
	}

}
